The goal of moveEZ is to create animated biplots.
You can install the development version of moveEZ from GitHub with:
Consider a dataset \({\bf{X}}\) comprising \(n\) observations and \(p\) continuous variables, along with an additional variable representing “time.” This time variable need not correspond to chronological time; it could just as well represent another form of ordered index, such as algorithmic iterations or experimental stages.
A natural approach is to construct separate biplots for each level of the time variable, enabling the user to explore how samples and variable relationships evolve across time. However, when the time variable includes many levels, this quickly results in an overwhelming number of biplots.
This package addresses that challenge by animating a single biplot across the levels of the time variable, allowing for dynamic visualisation of temporal or sequential changes in the data.
The animation of the biplots—currently limited to PCA biplots—is based on two conceptual frameworks:
Fixed Variable Frame moveplot(): A biplot is first
constructed using the full dataset \({\bf{X}}\), and the animation is achieved
by slicing the observations according to the “time” variable. In this
approach, the variable axes remain fixed, and only the sample points are
animated over time.
Dynamic Frame moveplot2(): Separate biplots are
constructed for each time slice of the data. Both the sample points and
variable axes evolve over time, resulting in a fully dynamic animation
that reflects temporal changes in the underlying data
structure.
To illustrate the animated biplots, we use a climate dataset included in the package. This dataset, Africa_climate, contains climate measurements from 10 African regions over time:
library(moveEZ)
data("Africa_climate")
tibble::tibble(Africa_climate)
#> # A tibble: 960 × 9
#> Year Month Region AccPrec DailyEva Temp SoilMois SPI6 wind
#> <fct> <fct> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1950 January ARP 0.177 0.0316 14.8 2.75 1.62 4.07
#> 2 1950 February ARP 0.208 -0.0249 15.4 2.22 1.32 4.24
#> 3 1950 March ARP 0.306 0.0122 20.9 2.08 0.987 4.04
#> 4 1950 April ARP 0.196 0.00396 24.8 1.73 0.916 3.72
#> 5 1950 May ARP 0.590 -0.0448 28.4 2.47 0.691 3.91
#> 6 1950 June ARP 0.32 -0.00754 30.4 1.17 0.249 4.40
#> 7 1950 July ARP 1.33 0.00184 30.8 2.00 0.673 4.93
#> 8 1950 August ARP 1.82 -0.00944 30.5 2.67 0.937 4.45
#> 9 1950 September ARP 0.706 -0.0107 29.7 1.98 1.22 3.67
#> 10 1950 October ARP 0.102 -0.0259 25.9 0.976 1.65 3.18
#> # ℹ 950 more rowsWe begin by constructing a standard PCA biplot using the
biplotEZ package. This biplot aggregates all samples across
time and colours them according to their associated region:
library(biplotEZ)
bp <- biplot(Africa_climate, scaled = TRUE) |>
PCA(group.aes = Africa_climate$Region) |>
samples(opacity = 0.8, col = scales::hue_pal()(10)) |>
plot()moveplot()Using the previously created PCA biplot object bp, the
moveplot() function enables animation of the sample points
over time. This function is piped with several key arguments:
time.var: Specifies the name of the variable in the
dataset that represents the temporal or sequential dimension. In this
case, the variable “Year” relates to the time variable.
group.var: Indicates a grouping variable used for
colour-coding. In this case, the variable “Region” relates to the group
variable.
hulls: A logical flag that determines whether to
display individual sample points or to draw convex hulls around each
group.
move: A critical argument that controls whether the
biplot is animated. If set to TRUE, the sample points are
animated across time. If set to FALSE, the function returns
a faceted plot showing a static biplot for each time level.
This design provides flexibility in exploring temporal dynamics in multivariate data, with options for both animated and comparative static visualisations.
move = FALSEmove = TRUE# Animated Z
bp |> moveplot(time.var = "Year", group.var = "Region", hulls = TRUE, move = TRUE)
#> Rendering [=>------------------------------------------------------------------------------------------------] at 8.7 fps ~ eta:
#> 11sRendering [==>-----------------------------------------------------------------------------------------------] at 9.2 fps ~ eta:
#> 11sRendering [===>-----------------------------------------------------------------------------------------------] at 10 fps ~ eta:
#> 10sRendering [====>----------------------------------------------------------------------------------------------] at 11 fps ~ eta:
#> 9sRendering [=====>---------------------------------------------------------------------------------------------] at 11 fps ~ eta:
#> 9sRendering [======>--------------------------------------------------------------------------------------------] at 11 fps ~ eta:
#> 8sRendering [=======>-------------------------------------------------------------------------------------------] at 11 fps ~ eta:
#> 8sRendering [========>------------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 8sRendering [=========>-----------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 8sRendering [==========>----------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [===========>---------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [============>--------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [=============>-------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [==============>------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [===============>-----------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [================>----------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [=================>---------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [==================>--------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [===================>-------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 6sRendering [====================>------------------------------------------------------------------------------] at 13 fps ~ eta:
#> 6sRendering [=====================>-----------------------------------------------------------------------------] at 13 fps ~ eta:
#> 6sRendering [======================>----------------------------------------------------------------------------] at 13 fps ~ eta:
#> 6sRendering [=======================>---------------------------------------------------------------------------] at 13 fps ~ eta:
#> 6sRendering [========================>--------------------------------------------------------------------------] at 13 fps ~ eta:
#> 6sRendering [=========================>-------------------------------------------------------------------------] at 13 fps ~ eta:
#> 6sRendering [==========================>------------------------------------------------------------------------] at 13 fps ~ eta:
#> 6sRendering [===========================>-----------------------------------------------------------------------] at 13 fps ~ eta:
#> 6sRendering [============================>----------------------------------------------------------------------] at 13 fps ~ eta:
#> 6sRendering [=============================>---------------------------------------------------------------------] at 13 fps ~ eta:
#> 6sRendering [==============================>--------------------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [===============================>-------------------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [================================>------------------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [=================================>-----------------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [==================================>----------------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [===================================>---------------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [====================================>--------------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [=====================================>-------------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [======================================>------------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [=======================================>-----------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [========================================>----------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [=========================================>---------------------------------------------------------] at 13 fps ~ eta:
#> 5sRendering [==========================================>--------------------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [===========================================>-------------------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [============================================>------------------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [=============================================>-----------------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [==============================================>----------------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [===============================================>---------------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [================================================>--------------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [=================================================>-------------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [==================================================>------------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [===================================================>-----------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [====================================================>----------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [=====================================================>---------------------------------------------] at 13 fps ~ eta:
#> 4sRendering [======================================================>--------------------------------------------] at 13 fps ~ eta:
#> 3sRendering [=======================================================>-------------------------------------------] at 13 fps ~ eta:
#> 3sRendering [========================================================>------------------------------------------] at 13 fps ~ eta:
#> 3sRendering [=========================================================>-----------------------------------------] at 13 fps ~ eta:
#> 3sRendering [==========================================================>----------------------------------------] at 13 fps ~ eta:
#> 3sRendering [===========================================================>---------------------------------------] at 13 fps ~ eta:
#> 3sRendering [============================================================>--------------------------------------] at 13 fps ~ eta:
#> 3sRendering [=============================================================>-------------------------------------] at 13 fps ~ eta:
#> 3sRendering [==============================================================>------------------------------------] at 13 fps ~ eta:
#> 3sRendering [===============================================================>-----------------------------------] at 13 fps ~ eta:
#> 3sRendering [================================================================>----------------------------------] at 13 fps ~ eta:
#> 3sRendering [=================================================================>---------------------------------] at 13 fps ~ eta:
#> 3sRendering [==================================================================>--------------------------------] at 13 fps ~ eta:
#> 3sRendering [===================================================================>-------------------------------] at 13 fps ~ eta:
#> 2sRendering [====================================================================>------------------------------] at 13 fps ~ eta:
#> 2sRendering [=====================================================================>-----------------------------] at 13 fps ~ eta:
#> 2sRendering [======================================================================>----------------------------] at 13 fps ~ eta:
#> 2sRendering [=======================================================================>---------------------------] at 13 fps ~ eta:
#> 2sRendering [========================================================================>--------------------------] at 13 fps ~ eta:
#> 2sRendering [=========================================================================>-------------------------] at 13 fps ~ eta:
#> 2sRendering [==========================================================================>------------------------] at 13 fps ~ eta:
#> 2sRendering [===========================================================================>-----------------------] at 13 fps ~ eta:
#> 2sRendering [============================================================================>----------------------] at 13 fps ~ eta:
#> 2sRendering [=============================================================================>---------------------] at 13 fps ~ eta:
#> 2sRendering [==============================================================================>--------------------] at 13 fps ~ eta:
#> 2sRendering [===============================================================================>-------------------] at 13 fps ~ eta:
#> 1sRendering [================================================================================>------------------] at 13 fps ~ eta:
#> 1sRendering [=================================================================================>-----------------] at 13 fps ~ eta:
#> 1sRendering [==================================================================================>----------------] at 13 fps ~ eta:
#> 1sRendering [===================================================================================>---------------] at 13 fps ~ eta:
#> 1sRendering [====================================================================================>--------------] at 13 fps ~ eta:
#> 1sRendering [=====================================================================================>-------------] at 13 fps ~ eta:
#> 1sRendering [======================================================================================>------------] at 13 fps ~ eta:
#> 1sRendering [=======================================================================================>-----------] at 13 fps ~ eta:
#> 1sRendering [========================================================================================>----------] at 13 fps ~ eta:
#> 1sRendering [=========================================================================================>---------] at 13 fps ~ eta:
#> 1sRendering [==========================================================================================>--------] at 13 fps ~ eta:
#> 1sRendering [===========================================================================================>-------] at 13 fps ~ eta:
#> 1sRendering [============================================================================================>------] at 13 fps ~ eta:
#> 0sRendering [=============================================================================================>-----] at 13 fps ~ eta:
#> 0sRendering [==============================================================================================>----] at 13 fps ~ eta:
#> 0sRendering [===============================================================================================>---] at 13 fps ~ eta:
#> 0sRendering [================================================================================================>--] at 13 fps ~ eta:
#> 0sRendering [=================================================================================================>-] at 13 fps ~ eta:
#> 0sRendering [===================================================================================================] at 13 fps ~ eta: 0smoveplot2()The moveplot2() function extends the animation to both
the sample points and the variable axes. Unlike moveplot(),
which keeps the variable axes fixed, moveplot2() constructs
a separate biplot for each time slice, allowing both components to
evolve over time. The function shares the same arguments as
moveplot(), with the move argument determining
whether the animation is shown or presented as static facets for samples
and variables.
move = FALSE
When
move is FALSE, a faceted plot is returned, showing the
biplot at each time point. Here, both the sample coordinates and
variable axes differ across facets, reflecting temporal changes in the
data structure.
move = TRUEbp |> moveplot2(time.var = "Year", group.var = "Region", hulls = TRUE, move = TRUE)
#> Rendering [==>------------------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 8sRendering [===>-----------------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 8sRendering [====>----------------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 8sRendering [=====>---------------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 8sRendering [======>--------------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 8sRendering [=======>-------------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 8sRendering [========>------------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 8sRendering [=========>-----------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [==========>----------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [===========>---------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [============>--------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [=============>-------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [==============>------------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [===============>-----------------------------------------------------------------------------------] at 12 fps ~ eta:
#> 7sRendering [================>----------------------------------------------------------------------------------] at 11 fps ~ eta:
#> 8sRendering [=================>---------------------------------------------------------------------------------] at 11 fps ~ eta:
#> 8sRendering [==================>--------------------------------------------------------------------------------] at 11 fps ~ eta:
#> 7sRendering [===================>-------------------------------------------------------------------------------] at 11 fps ~ eta:
#> 7sRendering [====================>------------------------------------------------------------------------------] at 11 fps ~ eta:
#> 7sRendering [=====================>-----------------------------------------------------------------------------] at 11 fps ~ eta:
#> 7sRendering [======================>----------------------------------------------------------------------------] at 11 fps ~ eta:
#> 7sRendering [=======================>---------------------------------------------------------------------------] at 11 fps ~ eta:
#> 7sRendering [========================>--------------------------------------------------------------------------] at 12 fps ~ eta:
#> 6sRendering [=========================>-------------------------------------------------------------------------] at 12 fps ~ eta:
#> 6sRendering [==========================>------------------------------------------------------------------------] at 12 fps ~ eta:
#> 6sRendering [===========================>-----------------------------------------------------------------------] at 12 fps ~ eta:
#> 6sRendering [============================>----------------------------------------------------------------------] at 12 fps ~ eta:
#> 6sRendering [=============================>---------------------------------------------------------------------] at 12 fps ~ eta:
#> 6sRendering [==============================>--------------------------------------------------------------------] at 12 fps ~ eta:
#> 6sRendering [===============================>-------------------------------------------------------------------] at 12 fps ~ eta:
#> 6sRendering [================================>------------------------------------------------------------------] at 12 fps ~ eta:
#> 6sRendering [=================================>-----------------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [==================================>----------------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [===================================>---------------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [====================================>--------------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [=====================================>-------------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [======================================>------------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [=======================================>-----------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [========================================>----------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [=========================================>---------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [==========================================>--------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [===========================================>-------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [============================================>------------------------------------------------------] at 12 fps ~ eta:
#> 5sRendering [=============================================>-----------------------------------------------------] at 12 fps ~ eta:
#> 4sRendering [==============================================>----------------------------------------------------] at 12 fps ~ eta:
#> 4sRendering [===============================================>---------------------------------------------------] at 12 fps ~ eta:
#> 4sRendering [================================================>--------------------------------------------------] at 12 fps ~ eta:
#> 4sRendering [=================================================>-------------------------------------------------] at 12 fps ~ eta:
#> 4sRendering [==================================================>------------------------------------------------] at 12 fps ~ eta:
#> 4sRendering [===================================================>-----------------------------------------------] at 12 fps ~ eta:
#> 4sRendering [====================================================>----------------------------------------------] at 12 fps ~ eta:
#> 4sRendering [=====================================================>---------------------------------------------] at 12 fps ~ eta:
#> 4sRendering [======================================================>--------------------------------------------] at 12 fps ~ eta:
#> 4sRendering [=======================================================>-------------------------------------------] at 12 fps ~ eta:
#> 4sRendering [========================================================>------------------------------------------] at 12 fps ~ eta:
#> 3sRendering [=========================================================>-----------------------------------------] at 12 fps ~ eta:
#> 3sRendering [==========================================================>----------------------------------------] at 12 fps ~ eta:
#> 3sRendering [===========================================================>---------------------------------------] at 12 fps ~ eta:
#> 3sRendering [============================================================>--------------------------------------] at 12 fps ~ eta:
#> 3sRendering [=============================================================>-------------------------------------] at 12 fps ~ eta:
#> 3sRendering [==============================================================>------------------------------------] at 12 fps ~ eta:
#> 3sRendering [===============================================================>-----------------------------------] at 12 fps ~ eta:
#> 3sRendering [================================================================>----------------------------------] at 12 fps ~ eta:
#> 3sRendering [=================================================================>---------------------------------] at 12 fps ~ eta:
#> 3sRendering [==================================================================>--------------------------------] at 12 fps ~ eta:
#> 3sRendering [===================================================================>-------------------------------] at 12 fps ~ eta:
#> 3sRendering [====================================================================>------------------------------] at 12 fps ~ eta:
#> 2sRendering [=====================================================================>-----------------------------] at 12 fps ~ eta:
#> 2sRendering [======================================================================>----------------------------] at 12 fps ~ eta:
#> 2sRendering [=======================================================================>---------------------------] at 12 fps ~ eta:
#> 2sRendering [========================================================================>--------------------------] at 12 fps ~ eta:
#> 2sRendering [=========================================================================>-------------------------] at 12 fps ~ eta:
#> 2sRendering [==========================================================================>------------------------] at 12 fps ~ eta:
#> 2sRendering [===========================================================================>-----------------------] at 12 fps ~ eta:
#> 2sRendering [============================================================================>----------------------] at 12 fps ~ eta:
#> 2sRendering [=============================================================================>---------------------] at 12 fps ~ eta:
#> 2sRendering [==============================================================================>--------------------] at 12 fps ~ eta:
#> 2sRendering [===============================================================================>-------------------] at 12 fps ~ eta:
#> 2sRendering [================================================================================>------------------] at 12 fps ~ eta:
#> 1sRendering [=================================================================================>-----------------] at 12 fps ~ eta:
#> 1sRendering [==================================================================================>----------------] at 12 fps ~ eta:
#> 1sRendering [===================================================================================>---------------] at 12 fps ~ eta:
#> 1sRendering [====================================================================================>--------------] at 12 fps ~ eta:
#> 1sRendering [=====================================================================================>-------------] at 12 fps ~ eta:
#> 1sRendering [======================================================================================>------------] at 12 fps ~ eta:
#> 1sRendering [=======================================================================================>-----------] at 12 fps ~ eta:
#> 1sRendering [========================================================================================>----------] at 12 fps ~ eta:
#> 1sRendering [=========================================================================================>---------] at 12 fps ~ eta:
#> 1sRendering [==========================================================================================>--------] at 12 fps ~ eta:
#> 1sRendering [===========================================================================================>-------] at 12 fps ~ eta:
#> 1sRendering [============================================================================================>------] at 12 fps ~ eta:
#> 0sRendering [=============================================================================================>-----] at 12 fps ~ eta:
#> 0sRendering [==============================================================================================>----] at 12 fps ~ eta:
#> 0sRendering [===============================================================================================>---] at 12 fps ~ eta:
#> 0sRendering [================================================================================================>--] at 12 fps ~ eta:
#> 0sRendering [=================================================================================================>-] at 12 fps ~ eta:
#> 0sRendering [===================================================================================================] at 12 fps ~ eta: 0sSetting move to TRUE produces an animated biplot in
which both the samples and variables transition across time, offering a
dynamic view of structural shifts in the multivariate space.
Watch this space! We are actively working on enhancing
moveplot2() by aligning the biplots across time slices.
This will allow for smoother transitions and more interpretable
animations when both samples and variable axes evolve.
Stay tuned for updates!